﻿using CKS.Core.Framework.Models;
using CKS.PLC.Core;
using CKS.PLC.Core.Event;
using Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using S7.Net;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    /// <summary>
    /// 订阅动作基类
    /// 可根据不同项目自行定义ActionId
    /// </summary>
    public abstract class BasePlcAction
    {
       public DecodeValue Value { get; set; }

        public PlcClient SiemensClient { get; set; }
        public BasePlcAction(DecodeValue _value) { 
            this.Value = _value;
            SiemensClient = this.Value.SiemensClient;
            serviceProvider = App.ServiceProvider.CreateScope().ServiceProvider;
        }

        public IServiceProvider serviceProvider;
        public ILogger<BasePlcAction> logger;
        public ISqlSugarClient db;
        public IFreeSql<MesDB> fsql;
        public DbConnection conn;
        public void InitConfig(IServiceProvider _serviceProvider,ISqlSugarClient sdb)
        {
            fsql =  serviceProvider.GetService<IFreeSql<MesDB>>();
            logger = serviceProvider.GetService<ILogger<BasePlcAction>>();
            db = sdb;
            conn=fsql.Ado.MasterPool.Get().Value;
        }
        /// <summary>
        /// 执行结束释放资源
        /// </summary>
        public void Close()
        {
            try
            {
                conn.Close();
            }
            catch (Exception)
            {

            }
        }


        /// <summary>
        /// 执行订阅事件
        /// </summary>
        public abstract void Execute();

        /// <summary>
        /// 信号复位，对该操作回复信号重置
        /// </summary>
        public void SignalReset()
        {
            //var points = Value.LinkPositions.FindAll(a=>a.DataKind == 2);
            //foreach (var p in points) {
            //    Value.plcSession.Write(S7.Net.DataType.DataBlock, p.BlockDb, p.BytePosition, Convert.ToInt16(0)); //
            //}
           
        }

       


        /// <summary>
        /// 读取单个点位的字符串数据
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public string ReadString(CksPlcDataPosition point)
        {
            var buffer = Value.plcSession.ReadBytes(DataType.DataBlock, point.BlockDb, (int)point.BytePosition, point.ByteLength);
           return DataConversion.GetStringDataByBytes(buffer, 0, buffer.Length);
        }

        public string ReadCacheString(CksPlcDataPosition point)
        {
            // Value.
            return Value.AllValues.Find(a => a.Position.Id == point.Id).Value.ToString();
            //var buffer = Value.plcSession.ReadBytes(DataType.DataBlock, point.BlockDb, point.BytePosition, point.ByteLenth);
            //return DataConversion.GetStringDataByBytes(buffer, 0, buffer.Length);
        }


        public int ReadInt16(CksPlcDataPosition point)
        {
            var buffer = Value.plcSession.ReadBytes(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition, point.ByteLength);
            return DataConversion.GetInt16DataByBytes(buffer, 0);
        }

        /// <summary>
        /// 向指定点位写入 int16--对应plc的int值
        /// </summary>
        /// <param name="point"></param>
        /// <param name="value"></param>
        private void WriteInt16(CksPlcDataPosition point,Int16 value)
        {
            Value.plcSession.Write(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition, Convert.ToInt16(value)); //
        
        }

        public bool AckWriteInt16(CksPlcDataPosition point, Int16 value)
        {
            for (int i = 1; i <= 10; i++)
            {
                WriteInt16(point, value);
              
                var write = ReadInt16(point);
                if (write == value)
                {
                    if(i>1)
                    {
                        EventBus.AddLog($"第{i}次写入点位{point.WorkStationCode}-{point.BlockDb}-{point.BytePosition}，计划写入:{value},查询结果:{write}，写入ok");
                    }
                    return true;
                }
                else
                    EventBus.AddLog($"第{i}次写入点位{point.WorkStationCode}-{point.BlockDb}-{point.BytePosition}，计划写入:{value},查询结果:{write}，不一致");
                Thread.Sleep(5);
                
            }

            throw new Exception($"写入点位{ point.WorkStationCode}-{point.BlockDb}-{ point.BytePosition }失败");
        }

        public void WriteInt16(int db, int startByteAdr, Int16 value)
        {
            Value.plcSession.Write(S7.Net.DataType.DataBlock, db, startByteAdr, Convert.ToInt16(value)); //
        }

        public void WriteString(CksPlcDataPosition point,string value)
        {
            // 编码为字节数组
            byte[] stringBytes = Encoding.ASCII.GetBytes(value);
            // 构建带控制信息的字节数组
            byte[] dataString = new byte[stringBytes.Length + 2]; // 加2是为了存储控制信息
                                                                  // 添加控制信息
            dataString[0] = (byte)(point.ByteLength - 2); //第一个字节是字符串的字节总数
            dataString[1] = (byte)(stringBytes.Length); // 第二个字节表示实际使用字节数量
                                                        // 复制字符串数据到字节数组
            Array.Copy(stringBytes, 0, dataString, 2, stringBytes.Length);
            // 将字节数组写入PLC
            Value.plcSession.WriteBytes(S7.Net.DataType.DataBlock, point.BlockDb, (int)point.BytePosition, dataString);
        }





        
    }
}
